package cn.rocksolid.proxy.restful.sys;

import cn.rocksolid.sport.agency.entity.AgencyEntity;
import cn.rocksolid.sport.agency.service.AgencyService;
import cn.rocksolid.sport.common.C;
import cn.rocksolid.sport.common.Constant.AccessType;
import cn.rocksolid.sport.common.context.RockSolidContextHolder;
import cn.rocksolid.sport.common.error.RSE;
import cn.rocksolid.sport.common.error.RockSolidException;
import cn.rocksolid.sport.common.http.R;
import cn.rocksolid.sport.common.http.utils.HttpUtils;
import cn.rocksolid.sport.common.utils.AssertUtils;
import cn.rocksolid.sport.security.entity.UserEntity;
import cn.rocksolid.sport.security.service.CredentialService;
import cn.rocksolid.sport.security.service.UserService;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

/**
 * System user service
 *
 * @author Axl Zhao
 * @email axl.zhao@163.com
 */
@RestController
@RequestMapping("/sys/user")
public class UserController {

  private final UserService userService;
  private final AgencyService agencyService;
  private final CredentialService credentialService;

  @Autowired
  public UserController(final UserService userService, final AgencyService agencyService,
          final CredentialService credentialService) {
    this.userService = userService;
    this.agencyService = agencyService;
    this.credentialService = credentialService;
  }

  /**
   * Pagination of system users
   */
  @PostMapping("/page")
  @RequiresPermissions("sys:user:info")
  public Object page(@RequestBody final JSONObject cond) {
    // TODO: below are exception verify codes.
    //    AssertUtils.isNotNull(null, RSE.DUP_ULOGID);
    //    return R.ok().put("page", userService.paging(HttpUtils.resolve(), userEntity));
    return userService.paging(HttpUtils.resolve(), cond);
  }

  /**
   * Get system user
   */
  @GetMapping("/{id}")
  @RequiresPermissions("sys:user:info")
  public Object get(@PathVariable("id") final String id) {
    return userService.get(id);
  }

  /**
   * Create new system user
   */
  @PutMapping
  @RequiresPermissions("sys:user:create")
  public Object create(@RequestBody final UserEntity userEntity) {
    validate(userEntity);
    AssertUtils.isNull(userService.exist(userEntity), RSE.DUP_ULOGID);
    userService.create(userEntity);
    return R.ok();
  }

  /**
   * modify system user
   */
  @PostMapping
  @RequiresPermissions("sys:user:modify")
  public Object modify(@RequestBody final UserEntity userEntity) {
    validate(userEntity);
    AssertUtils.isNull(userService.exist(userEntity), RSE.DUP_ULOGID);
    userService.modify(userEntity);
    return R.ok();
  }

  /**
   * remove system user
   */
  @DeleteMapping
  @RequiresPermissions("sys:user:remove")
  public R remove(@RequestBody final Collection<String> ids) {
    Collection<String> safeUids = CollectionUtils.emptyIfNull(ids);
    if (safeUids.contains(RockSolidContextHolder.getContextSafe().getAccessId())) {
      throw new RockSolidException(RSE.CU_CANNOT_REMOVE);
    }
    AgencyEntity agencyEntity = agencyService.getById(RockSolidContextHolder.getContextSafe().getAgencyId());
    if (safeUids.contains(agencyEntity.getAdminId())) {
      throw new RockSolidException(RSE.AA_CANNOT_REMOVE);
    }
    userService.removes(ids);
    return R.ok();
  }

  /**
   * Change password for current login
   */
  @PostMapping("/self-pwd")
  @RequiresPermissions("sys:user:self-modify")
  public R changeSelfPassword(@RequestBody final JSONObject data) {
    AssertUtils.isNotNull(data, RSE.INVALID_PAYLOAD);
    AssertUtils.isPassword(data.getString(C.PASSWORD_OLD.p), RSE.INVALID_PWD);
    AssertUtils.isPassword(data.getString(C.PASSWORD_NEW.p), RSE.INVALID_PWD);
    credentialService.verify(RockSolidContextHolder.getContextSafe().getAccessId(), AccessType.AGENCY,
            data.getString(C.PASSWORD_OLD.p));
    credentialService.refresh(RockSolidContextHolder.getContextSafe().getAccessId(), AccessType.AGENCY,
            data.getString(C.PASSWORD_NEW.p));
    return R.ok();
  }

  /**
   * Change password for others users
   */
  @PostMapping("/pwd")
  @RequiresPermissions("sys:user:modify")
  public R password(@RequestBody final JSONObject data) {
    AssertUtils.isNotNull(data, RSE.INVALID_PAYLOAD);
    AssertUtils.isUuid32(data.getString(C.ID.p), RSE.INVALID_UID);
    AssertUtils.isPassword(data.getString(C.PASSWORD_NEW.p), RSE.INVALID_PWD);
    credentialService.refresh(data.getString(C.ID.p), AccessType.AGENCY, data.getString(C.PASSWORD_NEW.p));
    return R.ok();
  }

  /**
   * system user validation
   */
  private void validate(final UserEntity user) {
    AssertUtils.isNotNull(user, RSE.INVALID_PAYLOAD);
    AssertUtils.isNotNull(user.getAvatar(), RSE.INVALID_UAVATAR);
    AssertUtils.isName(user.getUsername(), RSE.INVALID_UNAME);
    AssertUtils.isEmail(user.getEmail(), RSE.INVALID_EMAIL);
    AssertUtils.isMobile(user.getMobile(), RSE.INVALID_MOBILE);
  }
}
